/* eslint-disable operator-linebreak */
/* eslint-disable react/no-danger */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useRef } from 'react';
import { Collapse } from 'antd';
import hljs from 'highlight.js';
import MarkdownIt from 'markdown-it';
import context from '@/assets/images/advanceReact/context.png';
import redux from '@/assets/images/advanceReact/redux.png';
import reduxWorkflow from '@/assets/images/advanceReact/redux_workflow.png';

import 'highlight.js/styles/atom-one-light.css';
import './index.less';

const { Panel } = Collapse;
const mdParser = MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (error) {
        console.log(error);
      }
    }
    return ''; // 使用额外的默认转义
  },
});

export default function DataFlow() {
  const EventEmitter =
    '```js' +
    `
    class EventEmitter {
      constructor() {
        // eventMap 用来存储事件和监听函数之间的关系
        this.eventMap = {};
      }

      /**
       * @description: 负责注册事件的监听器，指定事件触发时的回调函数
       * @param {string} type 事件类型
       * @param {function} handler 回调用函数
       */
      on(type, handler) {
        if(!(handler instanceOf Function)) {
          throw '必须为一个函数～'
        }
        if(!this.eventMap[type]) {
          this.eventMap[type] = [];
        }
        this.eventMap[type].push(handler)
      }

      /**
       * @description: 负责触发事件，可以通过传参使其在触发的时候携带数据
       * @param {string} type 事件类型
       * @param {any} params 携带参数
       */
      emit(type, params) {
        if(this.eventMap[type]) {
          this.eventMap[type].forEach((handler, index) => {
            handler(params);
          })
        }
      }
      /**
       * @description: 负责监听器的删除
       * @param {string} type 事件类型
       * @param {function} handler 回调用函数
       */
      off(type, handler) {
        if(this.eventMap[type]) {
          this.eventMap[type].splice(this.eventMap.indexOf(handler) >>> 0, 1);
        }
      }
    }
  `;

  const contextCode =
    '```js' +
    `
    const AppContext = React.createContext(defaultValue);
    const {Provider, Consumer} = AppContext

    <Provider value={desc: '根组件包裹Provider'}>
      <SomeChild/>
    </Provider>

    <Consumer>
      {value => <div>{value.desc></div>}}
    </Consumer>
  `;

  const reduxCode =
    '```js' +
    `
    import {createStore} from 'redux';
    const store = createStore(
      reducer,
      initial_state,
      applyMiddleware(middleware1, middleware2, ...)
    );

    const reducer = (state, action) => {
      // 此处是state处理逻辑
      return new_state
    };

    store.dispatch(action);
`;
  return (
    <div className="advance-react-wrapper">
      <Collapse defaultActiveKey={['1', '2', '3', '4']}>
        <Panel header="基于props的单项数据流" key="1">
          <p>当前组件的state以props的形式流动时，只能流向组件树中比自己层级更低的组件。</p>
        </Panel>
        <Panel header="父子组件通信" key="2">
          父组件直接将state以props透传给子组件
        </Panel>
        <Panel header="子父组件通信" key="3">
          父组件传递给子组件的是一一个绑定了自身上下文的函数，那么子组件在调用该函数时，就可以将想要交给父组件的数据以函数入参的形式给出去
        </Panel>
        <Panel header="兄弟组件通信" key="4">
          <ul>
            <li>父子层级浅：利用共同的父组件，转换为父子组件、子父组件通信的关系。</li>
            <li>
              <Collapse>
                <Panel
                  header="发布订阅模式：最典型的例子就是document.addEventListener(type, func, useCapture)"
                  key="1"
                >
                  <div
                    className="code-wrapper"
                    dangerouslySetInnerHTML={{
                      __html: mdParser.render(EventEmitter),
                    }}
                  />
                </Panel>
              </Collapse>
            </li>
            <li>
              <Collapse>
                <Panel header="Context API：v16.3.0开始，改进后才提倡使用。" key="1">
                  <h4>原有的问题：</h4>
                  <ol>
                    <li>代码不够优雅，无法快速识别Provider和Consumer</li>
                    <li>
                      无法保证数据在生产者和消费者之间同步（context发生变化，但shouldComponentUpdate返回false，后代组件就不会更新，新的context即使返回false，也会透传）
                    </li>
                  </ol>
                  <div
                    className="code-wrapper"
                    dangerouslySetInnerHTML={{
                      __html: mdParser.render(contextCode),
                    }}
                  />
                </Panel>
              </Collapse>
            </li>
            <li>
              <Collapse>
                <Panel header="Redux：是JavaScript状态容器，它提供可预测的状态管理。" key="1">
                  <p>处理更加复杂的状况，不仅仅适用于react</p>
                  <div style={{ display: 'flex', gap: 20 }}>
                    <img src={redux} alt="" width="50%" />
                    <section>
                      <p>store: 单一数据源，只读</p>
                      <p>action: 对变化的描述，包括type和payload</p>
                      <p>reducer: 负责对变化进行分发和处理</p>
                    </section>
                  </div>
                  <div style={{ display: 'flex', gap: 20, marginTop: 20 }}>
                    <div
                      style={{ width: '50%' }}
                      className="code-wrapper"
                      dangerouslySetInnerHTML={{
                        __html: mdParser.render(reduxCode),
                      }}
                    />
                    <img src={reduxWorkflow} alt="" width="50%" />
                  </div>
                </Panel>
              </Collapse>
            </li>
          </ul>
        </Panel>
      </Collapse>
    </div>
  );
}
